columnview: Add sorting
authorMatthias Clasen <mclasen@redhat.com>
Wed, 4 Dec 2019 13:13:13 +0000 (08:13 -0500)
committerMatthias Clasen <mclasen@redhat.com>
Sat, 30 May 2020 23:26:46 +0000 (19:26 -0400)
This is a somewhat large commit that:

- Adds GtkColumnViewSorter
This is a special-purpose, private sorter implementation which sorts
according to multiple sorters, allowing each individual sorter to be
inverted. This will be used with clickable column view headers.

- Adds a read-only GtkColumnView::sorter property
The GtkColumnView creates a GtkColumnViewSorter at startup that it uses
for this property.

- Adds a writable GtkColumnViewColumn::sorter property
This allows defining per-column sorters. Whenever an application sets a
sorter for a column, the header becomes clickable and whenever
a header is clicked, that column's sorter is prepended to the list of
sorters, unless it is already the first sorter, in which case we invert
its order. No column can be in the list more than once.

12 files changed:
docs/reference/gtk/gtk4-sections.txt
docs/reference/gtk/meson.build
gtk/gtkcolumnview.c
gtk/gtkcolumnview.h
gtk/gtkcolumnviewcolumn.c
gtk/gtkcolumnviewcolumn.h
gtk/gtkcolumnviewcolumnprivate.h
gtk/gtkcolumnviewprivate.h
gtk/gtkcolumnviewsorter.c [new file with mode: 0644]
gtk/gtkcolumnviewsorterprivate.h [new file with mode: 0644]
gtk/meson.build
testsuite/gtk/defaultvalue.c

index 29fbba6b52d91744851d2c117b704779f87fc0d3..071d026d0725fd1ce0199b87cc8eb2a2e2e449c2 100644 (file)
@@ -500,6 +500,7 @@ gtk_column_view_remove_column
 gtk_column_view_get_columns
 gtk_column_view_get_model
 gtk_column_view_set_model
+gtk_column_view_get_sorter
 gtk_column_view_get_show_separators
 gtk_column_view_set_show_separators
 <SUBSECTION Standard>
@@ -524,6 +525,8 @@ gtk_column_view_column_set_factory
 gtk_column_view_column_get_factory
 gtk_column_view_column_set_title
 gtk_column_view_column_get_title
+gtk_column_view_column_set_sorter
+gtk_column_view_column_get_sorter
 <SUBSECTION Standard>
 GTK_COLUMN_VIEW_COLUMN
 GTK_COLUMN_VIEW_COLUMN_CLASS
index 40584ab31f6f0cb1e9b8110c54a6ea3c16f4b1e0..ddc9e9c6222c76b8b47a31c4f3cb590f5cf480c8 100644 (file)
@@ -29,6 +29,7 @@ private_headers = [
   'gtkcolumnviewcolumnprivate.h',
   'gtkcolumnviewlayoutprivate.h',
   'gtkcolumnviewprivate.h',
+  'gtkcolumnviewsorterprivate.h',
   'gtkcolumnviewtitleprivate.h',
   'gtkcomboboxprivate.h',
   'gtkconstraintexpressionprivate.h',
index d6170dfc460604b73fdd140a990d1b75e636553c..9d3bf9129971bc3d5cbdbb77e48349bd6968e34d 100644 (file)
@@ -26,6 +26,7 @@
 #include "gtkcolumnlistitemfactoryprivate.h"
 #include "gtkcolumnviewcolumnprivate.h"
 #include "gtkcolumnviewlayoutprivate.h"
+#include "gtkcolumnviewsorterprivate.h"
 #include "gtkcssnodeprivate.h"
 #include "gtkintl.h"
 #include "gtklistview.h"
  *
  * GtkColumnView is a widget to present a view into a large dynamic list of items
  * using multiple columns.
+ *
+ * It supports sorting that can be customized by the user by clicking on column
+ * view headers. To set this up, the #GtkSorter returned by gtk_column_view_get_sorter()
+ * must be attached to a sort model for the data that the view is showing, and the
+ * columns must have sorters attached to them by calling gtk_column_view_column_set_sorter().
+ * The initial sort order can be set with gtk_column_view_sort_by_column().
  */
 
 struct _GtkColumnView
@@ -54,6 +61,8 @@ struct _GtkColumnView
 
   GtkListView *listview;
   GtkColumnListItemFactory *factory;
+
+  GtkSorter *sorter;
 };
 
 struct _GtkColumnViewClass
@@ -69,6 +78,7 @@ enum
   PROP_HSCROLL_POLICY,
   PROP_MODEL,
   PROP_SHOW_SEPARATORS,
+  PROP_SORTER,
   PROP_VADJUSTMENT,
   PROP_VSCROLL_POLICY,
 
@@ -250,6 +260,8 @@ gtk_column_view_dispose (GObject *object)
   g_clear_pointer ((GtkWidget **) &self->listview, gtk_widget_unparent);
   g_clear_object (&self->factory);
 
+  g_clear_object (&self->sorter);
+
   G_OBJECT_CLASS (gtk_column_view_parent_class)->dispose (object);
 }
 
@@ -301,6 +313,10 @@ gtk_column_view_get_property (GObject    *object,
       g_value_set_enum (value, gtk_scrollable_get_vscroll_policy (GTK_SCROLLABLE (self->listview)));
       break;
 
+    case PROP_SORTER:
+      g_value_set_object (value, self->sorter);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -429,6 +445,18 @@ gtk_column_view_class_init (GtkColumnViewClass *klass)
                           FALSE,
                           G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
 
+  /**
+   * GtkColumnView:sorter:
+   *
+   * Sorter with the sorting choices of the user
+   */
+  properties[PROP_SORTER] =
+    g_param_spec_object ("sorter",
+                         P_("Sorter"),
+                         P_("Sorter with sorting choices of the user"),
+                         GTK_TYPE_SORTER,
+                         G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
   g_object_class_install_properties (gobject_class, N_PROPS, properties);
 
   /**
@@ -468,6 +496,7 @@ gtk_column_view_init (GtkColumnView *self)
   gtk_widget_set_layout_manager (self->header, gtk_column_view_layout_new (self));
   gtk_widget_set_parent (self->header, GTK_WIDGET (self));
 
+  self->sorter = gtk_column_view_sorter_new ();
   self->factory = gtk_column_list_item_factory_new (self);
   self->listview = GTK_LIST_VIEW (gtk_list_view_new_with_factory (
         GTK_LIST_ITEM_FACTORY (g_object_ref (self->factory))));
@@ -643,6 +672,7 @@ gtk_column_view_remove_column (GtkColumnView       *self,
         break;
     }
 
+  gtk_column_view_sorter_remove_column (GTK_COLUMN_VIEW_SORTER (self->sorter), column);
   gtk_column_view_column_set_column_view (column, NULL);
   g_list_store_remove (self->columns, i);
 }
@@ -681,3 +711,28 @@ gtk_column_view_get_header_widget (GtkColumnView *self)
   return GTK_LIST_ITEM_WIDGET (self->header);
 }
 
+/**
+ * gtk_column_view_get_sorter:
+ * @self: a #GtkColumnView
+ *
+ * Returns the sorter associated with users sorting choices in
+ * the column view.
+ *
+ * To allow users to customizable sorting by clicking on column
+ * headers, this sorter needs to be set on the sort
+ * model(s) underneath the model that is displayed
+ * by the view.
+ *
+ * See gtk_column_view_column_get_sorter() for setting up
+ * per-column sorting.
+ *
+ * Returns: (transfer none): the #GtkSorter of @self
+ */
+GtkSorter *
+gtk_column_view_get_sorter (GtkColumnView *self)
+{
+  g_return_val_if_fail (GTK_IS_COLUMN_VIEW (self), NULL);
+
+  return self->sorter;
+}
+
index a4ac08a8b14fe6a0b66ab6b07f83104fdee6c61c..6ec91319e8a83900f7d83274c6836c459bd0589f 100644 (file)
@@ -25,6 +25,8 @@
 #endif
 
 #include <gtk/gtktypes.h>
+#include <gtk/gtksortlistmodel.h>
+#include <gtk/gtksorter.h>
 
 G_BEGIN_DECLS
 
@@ -65,12 +67,16 @@ GListModel *    gtk_column_view_get_model                       (GtkColumnView
 GDK_AVAILABLE_IN_ALL
 void            gtk_column_view_set_model                       (GtkColumnView          *self,
                                                                  GListModel             *model);
+
 GDK_AVAILABLE_IN_ALL
 gboolean        gtk_column_view_get_show_separators             (GtkColumnView          *self);
 GDK_AVAILABLE_IN_ALL
 void            gtk_column_view_set_show_separators             (GtkColumnView          *self,
                                                                  gboolean                show_separators);
 
+GDK_AVAILABLE_IN_ALL
+GtkSorter *     gtk_column_view_get_sorter                      (GtkColumnView          *self);
+
 G_END_DECLS
 
 #endif  /* __GTK_COLUMN_VIEW_H__ */
index c33c50cd537f4b90b22870abb3b38411bcbd0f02..de240b0d4ead60dce4b02d7baa753fa02123e89a 100644 (file)
@@ -20,6 +20,7 @@
 #include "config.h"
 
 #include "gtkcolumnviewcolumnprivate.h"
+#include "gtkcolumnviewsorterprivate.h"
 
 #include "gtkcolumnviewprivate.h"
 #include "gtkcolumnviewtitleprivate.h"
@@ -32,6 +33,7 @@
 #include "gtksizegroup.h"
 #include "gtkstylecontext.h"
 #include "gtkwidgetprivate.h"
+#include "gtksorter.h"
 
 /**
  * SECTION:gtkcolumnviewcolumn
@@ -48,6 +50,7 @@ struct _GtkColumnViewColumn
 
   GtkListItemFactory *factory;
   char *title;
+  GtkSorter *sorter;
 
   /* data for the view */
   GtkColumnView *view;
@@ -73,6 +76,7 @@ enum
   PROP_COLUMN_VIEW,
   PROP_FACTORY,
   PROP_TITLE,
+  PROP_SORTER,
 
   N_PROPS
 };
@@ -90,6 +94,7 @@ gtk_column_view_column_dispose (GObject *object)
   g_assert (self->first_cell == NULL); /* no view = no children */
 
   g_clear_object (&self->factory);
+  g_clear_object (&self->sorter);
   g_clear_pointer (&self->title, g_free);
 
   G_OBJECT_CLASS (gtk_column_view_column_parent_class)->dispose (object);
@@ -117,6 +122,10 @@ gtk_column_view_column_get_property (GObject    *object,
       g_value_set_string (value, self->title);
       break;
 
+    case PROP_SORTER:
+      g_value_set_object (value, self->sorter);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -141,6 +150,10 @@ gtk_column_view_column_set_property (GObject      *object,
       gtk_column_view_column_set_title (self, g_value_get_string (value));
       break;
 
+    case PROP_SORTER:
+      gtk_column_view_column_set_sorter (self, g_value_get_object (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -192,6 +205,18 @@ gtk_column_view_column_class_init (GtkColumnViewColumnClass *klass)
                           NULL,
                           G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
 
+  /**
+   * GtkColumnViewColumn:sorter:
+   *
+   * Sorter for sorting items according to this column
+   */
+  properties[PROP_SORTER] =
+    g_param_spec_object ("sorter",
+                         P_("Sorter"),
+                         P_("Sorter for sorting items according to this column"),
+                         GTK_TYPE_SORTER,
+                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
   g_object_class_install_properties (gobject_class, N_PROPS, properties);
 }
 
@@ -552,3 +577,73 @@ gtk_column_view_column_get_title (GtkColumnViewColumn *self)
   return self->title;
 }
 
+#if 0
+static void
+gtk_column_view_column_add_to_sorter (GtkColumnViewColumn *self)
+{
+  if (self->view == NULL)
+    return;
+  
+  gtk_column_view_sorter_add_column (GTK_COLUMN_VIEW_SORTER (gtk_column_view_get_sorter (self->view)), self);
+}
+#endif
+
+static void
+gtk_column_view_column_remove_from_sorter (GtkColumnViewColumn *self)
+{
+  if (self->view == NULL)
+    return;
+  
+  gtk_column_view_sorter_remove_column (GTK_COLUMN_VIEW_SORTER (gtk_column_view_get_sorter (self->view)), self);
+}
+
+/**
+ * gtk_column_view_column_set_sorter:
+ * @self: a #GtkColumnViewColumn
+ * @sorter: (nullable): the #GtkSorter to associate with @column
+ *
+ * Associates a sorter with the column.
+ *
+ * This sorter can be made active by clicking on the column
+ * header, or by calling gtk_column_view_sort_by_column().
+ */
+void
+gtk_column_view_column_set_sorter (GtkColumnViewColumn *self,
+                                   GtkSorter           *sorter)
+{
+  g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self));
+  g_return_if_fail (sorter == NULL || GTK_IS_SORTER (sorter));
+
+  if (!g_set_object (&self->sorter, sorter))
+    return;
+
+  gtk_column_view_column_remove_from_sorter (self);
+
+  if (self->header)
+    gtk_column_view_title_update (GTK_COLUMN_VIEW_TITLE (self->header));
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SORTER]);
+}
+
+/**
+ * gtk_column_view_column_get_sorter:
+ * @self: a #GtkColumnViewColumn
+ *
+ * Returns the sorter that is associated with the column.
+ *
+ * Returns: (transfer none): the #GtkSorter of @self
+ */
+GtkSorter *
+gtk_column_view_column_get_sorter (GtkColumnViewColumn *self)
+{
+  g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self), NULL);
+
+  return self->sorter;
+}
+
+void
+gtk_column_view_column_notify_sort (GtkColumnViewColumn *self)
+{
+  if (self->header)
+    gtk_column_view_title_update (GTK_COLUMN_VIEW_TITLE (self->header));
+}
index 612cdb185416cdc332fc94e2168aa7eb2b1e79c8..f74cedaa084cd4d42a82f9664728ee86ca2aac89 100644 (file)
@@ -25,6 +25,7 @@
 #endif
 
 #include <gtk/gtkcolumnview.h>
+#include <gtk/gtksorter.h>
 
 G_BEGIN_DECLS
 
@@ -65,6 +66,12 @@ void                    gtk_column_view_column_set_title                (GtkColu
 GDK_AVAILABLE_IN_ALL
 const char *            gtk_column_view_column_get_title                (GtkColumnViewColumn    *self);
 
+GDK_AVAILABLE_IN_ALL
+void                    gtk_column_view_column_set_sorter               (GtkColumnViewColumn    *self,
+                                                                         GtkSorter              *sorter);
+GDK_AVAILABLE_IN_ALL
+GtkSorter *             gtk_column_view_column_get_sorter               (GtkColumnViewColumn    *self);
+
 G_END_DECLS
 
 #endif  /* __GTK_COLUMN_VIEW_COLUMN_H__ */
index d7e06a5b0fdaea3a3e396dffefc4a4883f46a1c6..fe46663e63af69f4fd7388901a78da4e810d3f4c 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "gtk/gtkcolumnviewcellprivate.h"
 
+
 void                    gtk_column_view_column_set_column_view          (GtkColumnViewColumn    *self,
                                                                          GtkColumnView          *view);
 
@@ -44,4 +45,6 @@ void                    gtk_column_view_column_get_allocation           (GtkColu
                                                                          int                    *offset,
                                                                          int                    *size);
 
+void                    gtk_column_view_column_notify_sort              (GtkColumnViewColumn    *self);
+
 #endif  /* __GTK_COLUMN_VIEW_COLUMN_PRIVATE_H__ */
index c356fae50894927c8f6e95d31deb46dc52e6fbd2..0d5cbbeed640d1e848d429d77f10295ef8882400 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "gtk/gtkcolumnview.h"
 
+#include "gtk/gtkcolumnviewsorterprivate.h"
 #include "gtk/gtklistitemwidgetprivate.h"
 
 GtkListItemWidget *     gtk_column_view_get_header_widget       (GtkColumnView          *self);
diff --git a/gtk/gtkcolumnviewsorter.c b/gtk/gtkcolumnviewsorter.c
new file mode 100644 (file)
index 0000000..d431de0
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Copyright © 2019 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen@redhat.com>
+ */
+
+#include "config.h"
+
+#include "gtkcolumnviewsorterprivate.h"
+
+#include "gtkcolumnviewcolumnprivate.h"
+#include "gtkintl.h"
+#include "gtktypebuiltins.h"
+
+typedef struct
+{
+  GtkColumnViewColumn *column;
+  GtkSorter *sorter;
+  gboolean   inverted;
+  gulong     changed_id;
+} Sorter;
+static void
+free_sorter (gpointer data)
+{
+  Sorter *s = data;
+
+  g_signal_handler_disconnect (s->sorter, s->changed_id);
+  g_object_unref (s->sorter);
+  g_object_unref (s->column);
+  g_free (s);
+}
+
+struct _GtkColumnViewSorter
+{
+  GtkSorter parent_instance;
+
+  GSequence *sorters;
+};
+
+G_DEFINE_TYPE (GtkColumnViewSorter, gtk_column_view_sorter, GTK_TYPE_SORTER)
+
+static GtkOrdering
+gtk_column_view_sorter_compare (GtkSorter *sorter,
+                                gpointer   item1,
+                                gpointer   item2)
+{
+  GtkColumnViewSorter *self = GTK_COLUMN_VIEW_SORTER (sorter);
+  GtkOrdering result = GTK_ORDERING_EQUAL;
+  GSequenceIter *iter;
+
+  for (iter = g_sequence_get_begin_iter (self->sorters);
+       !g_sequence_iter_is_end (iter);
+       iter = g_sequence_iter_next (iter))
+    {
+      Sorter *s = g_sequence_get (iter);
+
+      result = gtk_sorter_compare (s->sorter, item1, item2);
+      if (s->inverted)
+        result = - result;
+
+      if (result != GTK_ORDERING_EQUAL)
+        break;
+    }
+
+  return result;
+}
+
+static GtkSorterOrder
+gtk_column_view_sorter_get_order (GtkSorter *sorter)
+{
+  GtkColumnViewSorter *self = GTK_COLUMN_VIEW_SORTER (sorter);
+  GtkSorterOrder result = GTK_SORTER_ORDER_NONE;
+  GSequenceIter *iter;
+
+  for (iter = g_sequence_get_begin_iter (self->sorters);
+       !g_sequence_iter_is_end (iter);
+       iter = g_sequence_iter_next (iter))
+    {
+      Sorter *s = g_sequence_get (iter);
+
+      switch (gtk_sorter_get_order (s->sorter))
+        {
+          case GTK_SORTER_ORDER_PARTIAL:
+            result = GTK_SORTER_ORDER_PARTIAL;
+            break;
+          case GTK_SORTER_ORDER_NONE:
+            break;
+          case GTK_SORTER_ORDER_TOTAL:
+            return GTK_SORTER_ORDER_TOTAL;
+          default:
+            g_assert_not_reached ();
+            break;
+        }
+    }
+
+  return result;
+}
+
+static void
+gtk_column_view_sorter_dispose (GObject *object)
+{
+  GtkColumnViewSorter *self = GTK_COLUMN_VIEW_SORTER (object);
+
+  g_clear_pointer (&self->sorters, g_sequence_free);
+
+  G_OBJECT_CLASS (gtk_column_view_sorter_parent_class)->dispose (object);
+}
+
+static void
+gtk_column_view_sorter_class_init (GtkColumnViewSorterClass *class)
+{
+  GtkSorterClass *sorter_class = GTK_SORTER_CLASS (class);
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  sorter_class->compare = gtk_column_view_sorter_compare;
+  sorter_class->get_order = gtk_column_view_sorter_get_order;
+
+  object_class->dispose = gtk_column_view_sorter_dispose;
+}
+
+static void
+gtk_column_view_sorter_init (GtkColumnViewSorter *self)
+{
+  self->sorters = g_sequence_new (free_sorter);
+}
+
+GtkSorter *
+gtk_column_view_sorter_new (void)
+{
+  return g_object_new (GTK_TYPE_COLUMN_VIEW_SORTER, NULL);
+}
+
+static void
+gtk_column_view_sorter_changed_cb (GtkSorter *sorter, int change, gpointer data)
+{
+  gtk_sorter_changed (GTK_SORTER (data), GTK_SORTER_CHANGE_DIFFERENT);
+}
+
+static gboolean
+remove_column (GtkColumnViewSorter *self,
+               GtkColumnViewColumn *column)
+{
+  GSequenceIter *iter;
+
+  for (iter = g_sequence_get_begin_iter (self->sorters);
+       !g_sequence_iter_is_end (iter);
+       iter = g_sequence_iter_next (iter))
+    {
+      Sorter *s = g_sequence_get (iter);
+
+      if (s->column == column)
+        {
+          g_sequence_remove (iter);
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+gboolean
+gtk_column_view_sorter_add_column (GtkColumnViewSorter *self,
+                                   GtkColumnViewColumn *column)
+{
+  GSequenceIter *iter;
+  GtkSorter *sorter;
+  Sorter *s, *first;
+
+  g_return_val_if_fail (GTK_IS_COLUMN_VIEW_SORTER (self), FALSE);
+  g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (column), FALSE);
+
+  sorter = gtk_column_view_column_get_sorter (column);
+  if (sorter == NULL)
+    return FALSE;
+
+  iter = g_sequence_get_begin_iter (self->sorters);
+  if (!g_sequence_iter_is_end (iter))
+    {
+      first = g_sequence_get (iter);
+      if (first->column == column)
+        {
+          first->inverted = !first->inverted;
+          goto out;
+        }
+    }
+  else
+    first = NULL;
+
+  remove_column (self, column);
+
+  s = g_new (Sorter, 1);
+  s->column = g_object_ref (column);
+  s->sorter = g_object_ref (sorter);
+  s->changed_id = g_signal_connect (sorter, "changed", G_CALLBACK (gtk_column_view_sorter_changed_cb), self);
+  s->inverted = FALSE;
+  g_sequence_insert_before (iter, s);
+
+  /* notify the previous first column to stop drawing an arrow */
+  if (first)
+    gtk_column_view_column_notify_sort (first->column);
+
+out:
+  gtk_sorter_changed (GTK_SORTER (self), GTK_SORTER_CHANGE_DIFFERENT);
+
+  gtk_column_view_column_notify_sort (column);
+
+  return TRUE;
+}
+
+gboolean
+gtk_column_view_sorter_remove_column (GtkColumnViewSorter *self,
+                                      GtkColumnViewColumn *column)
+{
+  g_return_val_if_fail (GTK_IS_COLUMN_VIEW_SORTER (self), FALSE);
+  g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (column), FALSE);
+
+  if (remove_column (self, column))
+    {
+      gtk_sorter_changed (GTK_SORTER (self), GTK_SORTER_CHANGE_DIFFERENT);
+      gtk_column_view_column_notify_sort (column);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+void
+gtk_column_view_sorter_clear (GtkColumnViewSorter *self)
+{
+  GSequenceIter *iter;
+  Sorter *s;
+  GtkColumnViewColumn *column;
+
+  g_return_if_fail (GTK_IS_COLUMN_VIEW_SORTER (self));
+
+  if (g_sequence_is_empty (self->sorters))
+    return;
+
+  iter = g_sequence_get_begin_iter (self->sorters);
+  s = g_sequence_get (iter);
+  column = s->column;
+  g_sequence_remove_range (iter, g_sequence_get_end_iter (self->sorters));
+
+  gtk_sorter_changed (GTK_SORTER (self), GTK_SORTER_CHANGE_DIFFERENT);
+
+  gtk_column_view_column_notify_sort (column);
+}
+
+GtkColumnViewColumn *
+gtk_column_view_sorter_get_sort_column (GtkColumnViewSorter *self,
+                                        gboolean            *inverted)
+{
+  GSequenceIter *iter;
+  Sorter *s;
+
+  g_return_val_if_fail (GTK_IS_COLUMN_VIEW_SORTER (self), NULL);
+
+  if (g_sequence_is_empty (self->sorters))
+    return NULL;
+
+  iter = g_sequence_get_begin_iter (self->sorters);
+  s = g_sequence_get (iter);
+
+  *inverted = s->inverted;
+
+  return s->column;
+}
diff --git a/gtk/gtkcolumnviewsorterprivate.h b/gtk/gtkcolumnviewsorterprivate.h
new file mode 100644 (file)
index 0000000..ce89952
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2019 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen@redhat.com>
+ */
+
+#ifndef __GTK_COLUMN_VIEW_SORTER_H__
+#define __GTK_COLUMN_VIEW_SORTER_H__
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gdk/gdk.h>
+#include <gtk/gtksorter.h>
+#include <gtk/gtkcolumnviewcolumn.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_COLUMN_VIEW_SORTER             (gtk_column_view_sorter_get_type ())
+
+G_DECLARE_FINAL_TYPE (GtkColumnViewSorter, gtk_column_view_sorter, GTK, COLUMN_VIEW_SORTER, GtkSorter)
+
+GtkSorter *             gtk_column_view_sorter_new              (void);
+
+gboolean                gtk_column_view_sorter_add_column       (GtkColumnViewSorter    *self,
+                                                                 GtkColumnViewColumn    *column);
+gboolean                gtk_column_view_sorter_remove_column    (GtkColumnViewSorter    *self,
+                                                                 GtkColumnViewColumn    *column);
+
+void                    gtk_column_view_sorter_clear            (GtkColumnViewSorter    *self);
+
+GtkColumnViewColumn *   gtk_column_view_sorter_get_sort_column  (GtkColumnViewSorter    *self,
+                                                                 gboolean               *inverted);
+
+
+G_END_DECLS
+
+#endif /* __GTK_SORTER_H__ */
+
index 642904b231199e46de215d6bea20f0d067e96ca0..f53667a891026af312485d7bfe6fe45cdbfe4014 100644 (file)
@@ -199,6 +199,7 @@ gtk_public_sources = files([
   'gtkcolorutils.c',
   'gtkcolumnview.c',
   'gtkcolumnviewcolumn.c',
+  'gtkcolumnviewsorter.c',
   'gtkcombobox.c',
   'gtkcomboboxtext.c',
   'gtkcomposetable.c',
index 88b60463d5c4611fc4b2344d277d36e7790e8f5e..79ed6179f3e0394d78aab7416efbf0e7d976158b 100644 (file)
@@ -240,7 +240,8 @@ test_type (gconstpointer data)
        continue;
 
       if (g_type_is_a (type, GTK_TYPE_COLUMN_VIEW) &&
-         strcmp (pspec->name, "columns") == 0)
+          (strcmp (pspec->name, "columns") == 0 ||
+          strcmp (pspec->name, "sorter") == 0))
        continue;
 
 G_GNUC_BEGIN_IGNORE_DEPRECATIONS